package com.xzj.common.secure.util;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.xzj.common.core.exception.ServiceException;
import com.xzj.common.secure.annotation.XzjDecrypt;
import com.xzj.common.secure.annotation.XzjEncrypt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;

/**
 * @program: xzj-common
 * @ClassName: SecureAdviceUtil
 * @description: 加解密接口公用方法
 * @author: XiaZunJun
 * @create: 2024-08-06 08:53
 */
@Slf4j
public class SecureAdviceUtil {

    /**
     * 在读取 HTTP 请求内容之前对请求进行预处理
     *
     * @param inputMessage HTTP 请求消息对象，包含请求头和请求体
     * @param parameter    用于确定要处理的对象类型的方法参数
     * @param isDecrypt    是否需要对请求进行解密的标志
     * @return 处理后的 HTTP 请求消息对象，包含解密后的请求内容
     * @throws IOException
     */
    public static HttpInputMessage requestAdviceBeforeRead(HttpInputMessage inputMessage, MethodParameter parameter,boolean isDecrypt) throws IOException {
        String body = IoUtil.read(inputMessage.getBody(), StandardCharsets.UTF_8);
        if(StrUtil.isEmpty(body)){
            throw new ServiceException("Decrypt FAIL","请求参数body不能为空");
        }
        Object obj = JSON.parseObject(body, parameter.getParameterType());
        judgeParam(parameter.getParameterType(), isDecrypt, obj);
        HttpHeaders headers = inputMessage.getHeaders();
        headers.add("IS_DECRYPT", String.valueOf(isDecrypt));
        return new HttpInputMessage() {
            @Override
            public InputStream getBody() {
                return new ByteArrayInputStream(JSON.toJSONString(obj).getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                return headers;
            }
        };
    }

    private static void judgeParam(Class<?> parameterType, boolean isDecrypt, Object obj) {
        Field[] declaredFields = parameterType.getDeclaredFields();
        for(Field field: declaredFields){
            if(isDecrypt){
                judgeDecryptField(field, obj);
            }else{
                judgeEncryptField(field, obj);
            }
        }
        if(null != parameterType.getSuperclass()){
            judgeParam(parameterType.getSuperclass(), isDecrypt, obj);
        }
    }

    /**
     * 判断一个字段是否需要加密，并对其进行加密操作
     *
     * @param field 要检查的字段对象
     * @param obj   包含该字段的对象实例
     */
    public static void judgeEncryptField(Field field, Object obj) {
        XzjEncrypt xzjEncrypt1 = field.getAnnotation(XzjEncrypt.class);
        if(null != xzjEncrypt1){
            try {
                field.setAccessible(true);
                String secureValue = field.get(obj).toString();
                if(StrUtil.isNotEmpty(secureValue)){
                    field.set(obj, XzjSecureUtil.aesEncrypt(secureValue));
                }
            } catch (IllegalAccessException e) {
                throw new ServiceException("secure_fail",e.getMessage());
            }
        }
    }

    /**
     * 判断一个字段是否需要解密，并对其进行加密操作
     *
     * @param field 要检查的字段对象
     * @param obj   包含该字段的对象实例
     */
    public static void judgeDecryptField(Field field, Object obj) {
        XzjDecrypt xzjDecrypt = field.getAnnotation(XzjDecrypt.class);
        if(null != xzjDecrypt){
            try {
                field.setAccessible(true);
                String secureValue = field.get(obj).toString();
                if(StrUtil.isNotEmpty(secureValue)){
                    field.set(obj, XzjSecureUtil.aesDecrypt(secureValue));
                }
            } catch (IllegalAccessException e) {
                throw new ServiceException("secure_fail",e.getMessage());
            }
        }
    }
}
